Reading an expansion ROM from Open Firmware
1) Find out if the PCI card has an expansion ROM
To find out if the card has an expansion ROM we need to look at the Configuration Space header. Move down the device-tree to the card's node and look at the properties there using the .properties word. You should see something like this:
0 > .properties
vendor-id 00001000
device-id 00000004
revision-id 00000003
class-code 00010000
interrupts 00000001
min-grant 00000008
max-latency 00000040
devsel-speed 00000001
name pci1000,4
compatible pci1000,4
pciclass,010000
reg 00011800 00000000 00000000 00000000 00000000
01011810 00000000 00000000 00000000 00000100
02011814 00000000 00000000 00000000 00000100
02011830 00000000 00000000 00000000 00008000
assigned-addresses 81011810 00000000 00001000 00000000 00000100
82011830 00000000 80888000 00000000 00008000
82011814 00000000 80880000 00000000 00000100
|
(For an in-depth description of these properties see PCI Bus Binding to Open Firmware Rev. 2.1 (PDF file))
Notice the first long word in the "reg" property. This is the Configuration Space address of the device. We can use this address to look at the Header Type register in the Configuration header of the device.
The parent of our PCI plug in card is, in general, a PCI-PCI bridge. We need to open our parent so we can read the Header Type register in Configuration Space:
ok
0 > " .." find-device open ok
1 > . ffffffff
ok
0 >
|
Here the string " .." refers to our parent device. Calling find-device makes our parent the active package, and calling open prepares it for further use. After we call open we need to check the return value on the stack to see if the open was successful. We display the top stack item using the . word. A return value of 0xffffffff indicates success (true), and a return value of 0 indicates failure (false).
Once we have our parent node open we can read the Header Type register:
0 > 1180e config-b@ ok
1 > . 0
ok
0 >
|
The address 1180e is the Configuration Space address we want to read. The word config-b@ reads a byte from this address.
The . word displays the top item on the stack, which is the Header Type register. Since this is a Header Type Zero, we know the expansion ROM BAR is at offset 0x30 .
Looking at the assigned-addresses property we see an entry for a register at offset 0x30:
"assigned-addresses" property
82011830 00000000 80888000 00000000 00008000
(The low-byte of the first long word indicates the offset in Configuration Space)
|
So we know there is an expansion ROM that has been assigned a base address of 0x80888000 and is 0x8000 bytes long.
2) Enable the ROM
Bit 0 of the expansion ROM BAR enables the address decoder for the ROM. We can set bit 0 by reading in the BAR, OR-ing in 0x01 and writing this value to the BAR:
0 > 11830 dup config-l@ 1 or swap config-l! ok
|
3) Map the ROM into memory (Open Firmware only)
Since we're in Open Firmware, we need to manually map in the expansion ROM so we can read it. We can do this by using the do-map word. The base address assigned by Open Firmware can be found in the assigned-addresses property for the BAR:
82011830 00000000 80888000 00000000 00008000
|
The third long word, 0x80888000, is the address we want. The last long word, 0x00008000, is the length of the ROM. We can map in the ROM like this:
0 > 80888000 dup 8000 28 do-map ok
0 >
|
The do-map word creates an address translation. We pass it a physical address (80888000), a virtual address (the same address, put on the stack by the dup word), a length (8000), and a parameter (28).
The do-map word then calls the map method of the MMU to create the translation.
4) Enable Memory Space access to the card
By default, Open Firmware turns off Memory and I/O space accesses to plug-in cards. We can enable Memory space accesses by setting bit 1 of the command register (offset 0x04) in Configuration Space:
0 > 11804 dup config-w@ 2 or swap config-w! ok
0 >
|
5) Dump the ROM
Now assuming all has gone well we can us the base address and length of the ROM with the dump word to see the contents of the ROM:
0 > 80888000 100 dump
80888000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff :................:
80888010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff :................:
80888020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff :................:
80888030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff :................:
80888040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff :................:
80888050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff :................:
80888060: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff :................:
80888070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff :................:
80888080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff :................:
80888090: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff :................:
808880a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff :................:
808880b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff :................:
808880c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff :................:
808880d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff :................:
808880e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff :................:
808880f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff :................: ok
0 >
|
|